#include "dbimpl.h"
#include "fieldinfo.h"
#include "statement.h"
#include "tableinfo.h"

CDatabaseImpl::CDatabaseImpl(void)
{
}
CDatabaseImpl::~CDatabaseImpl(void)
{
}
HRESULT CDatabaseImpl::Init(IBase* pRot, IBase* pBase)
{
    HRESULT hr = S_OK;

    return hr;
}
HRESULT CDatabaseImpl::Uninit()
{
    HRESULT hr = S_OK;

    return hr;
}
HRESULT CDatabaseImpl::SetOption(LPCWSTR lpszName, LPCWSTR lpszValue)
{
    HRESULT hr = S_OK;

    m_lstOption[lpszName] = lpszValue;

    return hr;
}
HRESULT CDatabaseImpl::Connect()
{
    HRESULT hr = S_OK;
    LPCWSTR szFile = NULL;
    CHAR szFileUtf8[MAX_PATH + 1] = {0x00};
    std::map<std::wstring, std::wstring>::iterator it;
    for (it = m_lstOption.begin(); it != m_lstOption.end(); it++) {
        if (it->first.compare(L"database") == 0) {
            szFile = it->second.c_str();
        }
    }

    string strPath;
    int rc = sqlite3_open(strPath.c_str(), &m_pDB);
    rc_error(rc == SQLITE_OK, E_FAIL);

    sqlite3_busy_timeout(m_pDB, 10000);

    return hr;
}
UINT CDatabaseImpl::IsValid()
{
    return S_SUCCESS;
}
HRESULT CDatabaseImpl::Close()
{
    HRESULT hr = S_OK;
    int rc = sqlite3_close(m_pDB);
    rc_error(rc == SQLITE_OK, E_FAIL);
    return hr;
}

HRESULT CDatabaseImpl::CreateStatement(IStatement** ppStatement)
{
    CStatementImpl* p = ALLOC_NEW CStatementImpl(m_pDB);
    rc_error(p != NULL, E_FAIL);
    return p->QueryInterface(IID_IStatement, (void**)ppStatement);
}

UINT CDatabaseImpl::IsTableExist(LPCSTR lpszName)
{
    char szSQL[1024] = {0x00};
    int rc = SQLITE_OK;

    sprintf(szSQL, "select count(*) from sqlite_master where type='table' and name='%s'", lpszName);

    StmtPtr pStmt = compile(m_pDB, szSQL);
    rc_error(pStmt != NULL, E_FAIL);

    rc = sqlite3_step(pStmt);
    rc_error(rc == SQLITE_ROW, S_ERROR);

    rc = sqlite3_column_int(pStmt, 0);
    rc_error(rc == SQLITE_OK, S_SUCCESS);

    return S_ERROR;
}
HRESULT CDatabaseImpl::GetTableInfo(LPCSTR lpszName, ITableInfo** ppTableInfo)
{
    int nRet = 0;
    char szSQL[128] = {0x00};
    const char* pTail = NULL;
    std::string strTypeName;
    std::string strNotNull;
    std::string strPK;

    sprintf(szSQL, "%s%s%s", "PRAGMA table_info('", lpszName, "')");

    StmtPtr pStmt = compile(m_pDB, szSQL);
    rc_error(pStmt.m_p != NULL, E_FAIL);

    while (sqlite3_step(pStmt) == SQLITE_ROW) {
        _lComPtr<IFieldInfo> pFieldInfo;
        pFieldInfo.dispose();

        int nFlag = 0;

        HRESULT hr = CXFieldInfo::CreateInstance((IFieldInfo**)&pFieldInfo);
        rc_error_continue(hr == S_OK);

        pFieldInfo->SetName((char*)sqlite3_column_text(pStmt, FIELD_NAME_INDEX));
        strTypeName = (char*)sqlite3_column_text(pStmt, FIELD_TYPE_INDEX);
        strNotNull = (char*)sqlite3_column_text(pStmt, FIELD_ISNULL_INDEX);
        strPK = (char*)sqlite3_column_text(pStmt, FIELD_PK_INDEX);
        if (atoi(strNotNull.c_str()) == FIELD_IS_NOTNULL) {
            nFlag = FF_NOT_NULL;
        }
        if (atoi(strPK.c_str()) == FIELD_IS_PK) {
            nFlag = FF_PRI_KEY;
        }
        pFieldInfo->SetFlag(nFlag);
        pFieldInfo->SetTypeName(strTypeName.c_str());
        pFieldInfo->SetType(sqlite_string_to_type(strTypeName.c_str()));
        pFieldInfo->SetDefault("0");
        (*ppTableInfo)->Add(pFieldInfo);
    }

    return S_OK;
}
HRESULT CDatabaseImpl::UpdateTable(ITableInfo* pTableInfo)
{
    HRESULT hr = S_OK;

    rc_error(pTableInfo != NULL, E_FAIL);

    UINT uloop = 0;
    UINT uCount = pTableInfo->GetFieldCount();

    rc_error(uCount != 0, S_OK);

    string strCreateSql = "CREATE TABLE IF NOT EXISTS ";
    strCreateSql += pTableInfo->GetName();
    strCreateSql += "(";

    for (uloop = 0; uloop < uCount; uloop++) {
        _lComPtr<IFieldInfo> pField;
        pField.dispose();

        string strField;

        pTableInfo->GetField(uloop, &pField.m_p);

        if (pField != NULL) {
            strField += pField->GetName();
            strField += " ";
            strField += pField->GetTypeName();
            strField += " ";

            if (FF_PRI_KEY & pField->GetFlag()) {
                strField += "PRIMARY KEY ";
            }

            if (FF_AUTO_INCREMENT & pField->GetFlag()) {
                strField += "AUTOINCREMENT ";
            }

            if (FF_NOT_NULL & pField->GetFlag()) {
                strField += "NOT NULL ";
            }
            strField += ",";
            strCreateSql += strField;
        }
    }

    strCreateSql += ")";

    _lComPtr<IStatement> Statement;
    CreateStatement(&Statement.m_p);
    Statement->Execute(strCreateSql.c_str(), strCreateSql.length());
    return S_OK;
}
HRESULT CDatabaseImpl::CreateTableInfo(LPCSTR lpszName, ITableInfo** ppTableInfo)
{
    return CXTableInfo::CreateInstance(lpszName, ppTableInfo);
}
